﻿using System.Diagnostics.Contracts;
using MathService;

namespace System
{
    /// <summary>Расширения для чисел двойной точности</summary>
    public static class DoubleExtentions
    {
        /// <summary>Является ли число целым?</summary>
        /// <param name="x">Проверяемое число</param>
        /// <returns>Истина, если число целое</returns>
        [Diagnostics.DebuggerStepThrough]
        public static bool IsInt(this double x) { return Math.Abs(Math.Round(x) - x) < double.Epsilon; }

        [Diagnostics.DebuggerStepThrough]
        public static double Round(this double x, int n = 0) { return Math.Round(x, n); }

        /// <summary>Получить обратное число</summary>
        /// <param name="x">Инвертируемое число</param>
        /// <returns>Число, обратное к исходном</returns>
        [Diagnostics.DebuggerStepThrough]
        public static double GetInverse(this double x) { return 1 / x; }

        [Diagnostics.DebuggerStepThrough, Pure]
        public static double GetAbsMod(this double x, double mod) { return x % mod + (x < 0 ? mod : 0); }

        [Diagnostics.DebuggerStepThrough, Pure]
        public static double GetAbs(this double x) { return Math.Abs(x); }

        [Diagnostics.DebuggerStepThrough]
        public static double Power(this double x, int n)
        {
            if(n > 1000 || n < -1000) return Math.Pow(x, n);
            if(n < 0) return (1 / x).Power(-n);
            var result = 1.0;
            for(var i = 0; i < n; i++)
                result *= x;
            return result;
        }

        [Diagnostics.DebuggerStepThrough]
        public static double Power(this double x, double y) { return Math.Pow(x, y); }

        [Diagnostics.DebuggerStepThrough]
        public static Complex Power(this double x, Complex z) { return x ^ z; }

        [Diagnostics.DebuggerStepThrough]
        public static double In_dB(this double x) { return 20 * Math.Log10(x); }
        [Diagnostics.DebuggerStepThrough]
        public static double In_dB_byPower(this double x) { return 10 * Math.Log10(x); }

        [Diagnostics.DebuggerStepThrough]
        public static double From_dB(this double db) { return Math.Pow(10, db / 20); }
        [Diagnostics.DebuggerStepThrough]
        public static double From_dB_byPower(this double db) { return Math.Pow(10, db / 10); }

        [Diagnostics.DebuggerStepThrough]
        public static double ToRad(this double deg) { return deg * Consts.Geometry.ToRad; }
        [Diagnostics.DebuggerStepThrough]
        public static double ToDeg(this double rad) { return rad * Consts.Geometry.ToDeg; }
    }
}
